//package android.support.v4.widget;
//
///*
// * Copyright (C) 2013 The Android Open Source Project
// *
// * Licensed under the Apache License, Version 2.0 (the "License");
// * you may not use this file except in compliance with the License.
// * You may obtain a copy of the License at
// *
// *      http://www.apache.org/licenses/LICENSE-2.0
// *
// * Unless required by applicable law or agreed to in writing, software
// * distributed under the License is distributed on an "AS IS" BASIS,
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// * See the License for the specific language governing permissions and
// * limitations under the License.
// *
// */
//
//import android.content.Context;
//import android.content.res.Resources;
//import android.content.res.TypedArray;
//import android.support.v4.view.MotionEventCompat;
//import android.support.v4.view.ViewCompat;
//import android.support.v4.widget.CircleImageView;
//import android.support.v4.widget.MaterialProgressDrawable;
//import android.support.v4.widget.SwipeRefreshLayout;
//import android.support.v7.widget.RecyclerView;
//import android.util.AttributeSet;
//import android.util.DisplayMetrics;
//import android.util.Log;
//import android.view.MotionEvent;
//import android.view.View;
//import android.view.ViewConfiguration;
//import android.view.ViewGroup;
//import android.view.animation.Animation;
//import android.view.animation.DecelerateInterpolator;
//import android.view.animation.Transformation;
//import android.widget.AbsListView;
//
//
///**
// * The SwipeRefreshLayout should be used whenever the user can refresh the
// * contents of a view via a vertical swipe gesture. The activity that
// * instantiates this view should add an OnRefreshListener to be notified
// * whenever the swipe to refresh gesture is completed. The SwipeRefreshLayout
// * will notify the listener each and every time the gesture is completed again;
// * the listener is responsible for correctly determining when to actually
// * initiate a refresh of its content. If the listener determines there should
// * not be a refresh, it must call setRefreshing(false) to cancel any visual
// * indication of a refresh. If an activity wishes to show just the progress
// * animation, it should call setRefreshing(true). To disable the gesture and
// * progress animation, call setEnabled(false) on the view.
// * <p>
// * This layout should be made the parent of the view that will be refreshed as a
// * result of the gesture and can only support one direct child. This view will
// * also be made the target of the gesture and will be forced to match both the
// * width and the height supplied in this layout. The SwipeRefreshLayout does not
// * provide accessibility events; instead, a menu item must be provided to allow
// * refresh of the content wherever this gesture is used.
// * </p>
// *
// * fix bug version---
// * http://code.google.com/p/android/issues/detail?id=78191
// */
//public class MySwipeRefreshLayout extends ViewGroup {
//    // Maps to ProgressBar.Large style
//    public static final int LARGE = MaterialProgressDrawable.LARGE;
//    // Maps to ProgressBar default style
//    public static final int DEFAULT = MaterialProgressDrawable.DEFAULT;
//
//    private static final String LOG_TAG = SwipeRefreshLayout.class.getSimpleName();
//
//    private static final int MAX_ALPHA = 255;
//    private static final int STARTING_PROGRESS_ALPHA = (int) (.3f * MAX_ALPHA);
//
//    private static final int CIRCLE_DIAMETER = 40;
//    private static final int CIRCLE_DIAMETER_LARGE = 56;
//
//    private static final float DECELERATE_INTERPOLATION_FACTOR = 2f;
//    private static final int INVALID_POINTER = -1;
//    private static final float DRAG_RATE = .5f;
//
//    // Max amount of circle that can be filled by progress during swipe gesture,
//    // where 1.0 is a full circle
//    private static final float MAX_PROGRESS_ANGLE = .8f;
//
//    private static final int SCALE_DOWN_DURATION = 150;
//
//    private static final int ALPHA_ANIMATION_DURATION = 300;
//
//    private static final int ANIMATE_TO_TRIGGER_DURATION = 200;
//
//    private static final int ANIMATE_TO_START_DURATION = 200;
//
//    // Default background for the progress spinner
//    private static final int CIRCLE_BG_LIGHT = 0xFFFAFAFA;
//    // Default offset in dips from the top of the view to where the progress spinner should stop
//    private static final int DEFAULT_CIRCLE_TARGET = 64;
//
//    private View mTarget; // the target of the gesture
//    private OnRefreshListener mListener;
//    private boolean mRefreshing = false;
//    private int mTouchSlop;
//    private float mTotalDragDistance = -1;
//    private int mMediumAnimationDuration;
//    private int mCurrentTargetOffsetTop;
//    // Whether or not the starting offset has been determined.
//    private boolean mOriginalOffsetCalculated = false;
//
//    private float mInitialMotionY;
//    private boolean mIsBeingDragged;
//    private int mActivePointerId = INVALID_POINTER;
//    // Whether this item is scaled up rather than clipped
//    private boolean mScale;
//
//    // Target is returning to its start offset because it was cancelled or a
//    // refresh was triggered.
//    private boolean mReturningToStart;
//    private final DecelerateInterpolator mDecelerateInterpolator;
//    private static final int[] LAYOUT_ATTRS = new int[] {
//            android.R.attr.enabled
//    };
//
//    private CircleImageView mCircleView;
//    private int mCircleViewIndex = -1;
//
//    protected int mFrom;
//
//    private float mStartingScale;
//
//    protected int mOriginalOffsetTop;
//
//    private MaterialProgressDrawable mProgress;
//
//    private Animation mScaleAnimation;
//
//    private Animation mScaleDownAnimation;
//
//    private Animation mAlphaStartAnimation;
//
//    private Animation mAlphaMaxAnimation;
//
//    private Animation mScaleDownToStartAnimation;
//
//    private float mSpinnerFinalOffset;
//
//    private boolean mNotify;
//
//    private int mCircleWidth;
//
//    private int mCircleHeight;
//
//    // Whether the client has set a custom starting position;
//    private boolean mUsingCustomStart;
//
//    private Animation.AnimationListener mRefreshListener = new Animation.AnimationListener() {
//        @Override
//        public void onAnimationStart(Animation animation) {
//        }
//
//        @Override
//        public void onAnimationRepeat(Animation animation) {
//        }
//
//        @Override
//        public void onAnimationEnd(Animation animation) {
//            if (mRefreshing) {
//                // Make sure the progress view is fully visible
//                mProgress.setAlpha(MAX_ALPHA);
//                mProgress.start();
//                if (mNotify) {
//                    if (mListener != null) {
//                        mListener.onRefresh();
//                    }
//                }
//            } else {
//                mProgress.stop();
//                mCircleView.setVisibility(View.GONE);
//                setColorViewAlpha(MAX_ALPHA);
//                // Return the circle to its start position
//                if (mScale) {
//                    setAnimationProgress(0 /* animation complete and view is hidden */);
//                } else {
//                    setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCurrentTargetOffsetTop,
//                            true /* requires update */);
//                }
//            }
//            mCurrentTargetOffsetTop = mCircleView.getTop();
//        }
//    };
//    private static final String TAG = "MySwipeRefreshLayout";
//
//    private void setColorViewAlpha(int targetAlpha) {
//        mCircleView.getBackground().setAlpha(targetAlpha);
//        mProgress.setAlpha(targetAlpha);
//    }
//
//    /**
//     * The refresh indicator starting and resting position is always positioned
//     * near the top of the refreshing content. This position is a consistent
//     * location, but can be adjusted in either direction based on whether or not
//     * there is a toolbar or actionbar present.
//     *
//     * @param scale Set to true if there is no view at a higher z-order than
//     *            where the progress spinner is set to appear.
//     * @param start The offset in pixels from the top of this view at which the
//     *            progress spinner should appear.
//     * @param end The offset in pixels from the top of this view at which the
//     *            progress spinner should come to rest after a successful swipe
//     *            gesture.
//     */
//    public void setProgressViewOffset(boolean scale, int start, int end) {
//        mScale = scale;
//        mCircleView.setVisibility(View.GONE);
//        mOriginalOffsetTop = mCurrentTargetOffsetTop = start;
//        mSpinnerFinalOffset = end;
//        mUsingCustomStart = true;
//        mCircleView.invalidate();
//    }
//
//    /**
//     * The refresh indicator resting position is always positioned near the top
//     * of the refreshing content. This position is a consistent location, but
//     * can be adjusted in either direction based on whether or not there is a
//     * toolbar or actionbar present.
//     *
//     * @param scale Set to true if there is no view at a higher z-order than
//     *            where the progress spinner is set to appear.
//     * @param end The offset in pixels from the top of this view at which the
//     *            progress spinner should come to rest after a successful swipe
//     *            gesture.
//     */
//    public void setProgressViewEndTarget(boolean scale, int end) {
//        mSpinnerFinalOffset = end;
//        mScale = scale;
//        mCircleView.invalidate();
//    }
//
//    /**
//     * One of DEFAULT, or LARGE.
//     */
//    public void setSize(int size) {
//        if (size != MaterialProgressDrawable.LARGE && size != MaterialProgressDrawable.DEFAULT) {
//            return;
//        }
//        final DisplayMetrics metrics = getResources().getDisplayMetrics();
//        if (size == MaterialProgressDrawable.LARGE) {
//            mCircleHeight = mCircleWidth = (int) (CIRCLE_DIAMETER_LARGE * metrics.density);
//        } else {
//            mCircleHeight = mCircleWidth = (int) (CIRCLE_DIAMETER * metrics.density);
//        }
//        // force the bounds of the progress circle inside the circle view to
//        // update by setting it to null before updating its size and then
//        // re-setting it
//        mCircleView.setImageDrawable(null);
//        mProgress.updateSizes(size);
//        mCircleView.setImageDrawable(mProgress);
//    }
//
//    /**
//     * Simple constructor to use when creating a SwipeRefreshLayout from code.
//     *
//     * @param context
//     */
//    public MySwipeRefreshLayout(Context context) {
//        this(context, null);
//    }
//
//    /**
//     * Constructor that is called when inflating SwipeRefreshLayout from XML.
//     *
//     * @param context
//     * @param attrs
//     */
//    public MySwipeRefreshLayout(Context context, AttributeSet attrs) {
//        super(context, attrs);
//
//        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
//
//        mMediumAnimationDuration = getResources().getInteger(
//                android.R.integer.config_mediumAnimTime);
//
//        setWillNotDraw(false);
//        mDecelerateInterpolator = new DecelerateInterpolator(DECELERATE_INTERPOLATION_FACTOR);
//
//        final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
//        setEnabled(a.getBoolean(0, true));
//        a.recycle();
//
//        final DisplayMetrics metrics = getResources().getDisplayMetrics();
//        mCircleWidth = (int) (CIRCLE_DIAMETER * metrics.density);
//        mCircleHeight = (int) (CIRCLE_DIAMETER * metrics.density);
//
//        createProgressView();
//        ViewCompat.setChildrenDrawingOrderEnabled(this, true);
//        // the absolute offset has to take into account that the circle starts at an offset
//        mSpinnerFinalOffset = DEFAULT_CIRCLE_TARGET * metrics.density;
//        mTotalDragDistance = mSpinnerFinalOffset;
//    }
//
//    protected int getChildDrawingOrder(int childCount, int i) {
//        if (mCircleViewIndex < 0) {
//            return i;
//        } else if (i == childCount - 1) {
//            // Draw the selected child last
//            return mCircleViewIndex;
//        } else if (i >= mCircleViewIndex) {
//            // Move the children after the selected child earlier one
//            return i + 1;
//        } else {
//            // Keep the children before the selected child the same
//            return i;
//        }
//    }
//
//    private void createProgressView() {
//        mCircleView = new CircleImageView(getContext(), CIRCLE_BG_LIGHT);
//        mProgress = new MaterialProgressDrawable(getContext(), this);
//        mProgress.setBackgroundColor(CIRCLE_BG_LIGHT);
//        mCircleView.setImageDrawable(mProgress);
//        mCircleView.setVisibility(View.GONE);
//        addView(mCircleView);
//    }
//
//    /**
//     * Set the listener to be notified when a refresh is triggered via the swipe
//     * gesture.
//     */
//    public void setOnRefreshListener(OnRefreshListener listener) {
//        mListener = listener;
//    }
//
//    /**
//     * Pre API_URL 11, alpha is used to make the progress circle appear instead of scale.
//     */
//    private boolean isAlphaUsedForScale() {
//        return android.os.Build.VERSION.SDK_INT < 11;
//    }
//
//    /**
//     * Notify the widget that refresh state has changed. Do not call this when
//     * refresh is triggered by a swipe gesture.
//     *
//     * @param refreshing Whether or not the view should show refresh progress.
//     */
//    public void setRefreshing(boolean refreshing) {
//        if (refreshing && mRefreshing != refreshing) {
//            // scale and show
//            mRefreshing = refreshing;
//            int endTarget = 0;
//            if (!mUsingCustomStart) {
//                endTarget = (int) (mSpinnerFinalOffset + mOriginalOffsetTop);
//            } else {
//                endTarget = (int) mSpinnerFinalOffset;
//            }
//            setTargetOffsetTopAndBottom(endTarget - mCurrentTargetOffsetTop,
//                    true /* requires update */);
//            mNotify = false;
//            startScaleUpAnimation(mRefreshListener);
//        } else {
//            setRefreshing(refreshing, false /* notify */);
//        }
//    }
//
//    private void startScaleUpAnimation(Animation.AnimationListener listener) {
//        mCircleView.setVisibility(View.VISIBLE);
//        if (android.os.Build.VERSION.SDK_INT >= 11) {
//            // Pre API_URL 11, alpha is used in place of scale up to show the
//            // progress circle appearing.
//            // Don't adjust the alpha during appearance otherwise.
//            mProgress.setAlpha(MAX_ALPHA);
//        }
//        mScaleAnimation = new Animation() {
//            @Override
//            public void applyTransformation(float interpolatedTime, Transformation t) {
//                setAnimationProgress(interpolatedTime);
//            }
//        };
//        mScaleAnimation.setDuration(mMediumAnimationDuration);
//        if (listener != null) {
//            mCircleView.setAnimationListener(listener);
//        }
//        mCircleView.clearAnimation();
//        mCircleView.startAnimation(mScaleAnimation);
//    }
//
//    /**
//     * Pre API_URL 11, this does an alpha animation.
//     * @param progress
//     */
//    private void setAnimationProgress(float progress) {
//        if (isAlphaUsedForScale()) {
//            setColorViewAlpha((int) (progress * MAX_ALPHA));
//        } else {
//            ViewCompat.setScaleX(mCircleView, progress);
//            ViewCompat.setScaleY(mCircleView, progress);
//        }
//    }
//
//    public void setRefreshing(boolean refreshing, final boolean notify) {
//        if (mRefreshing != refreshing) {
//            mNotify = notify;
//            ensureTarget();
//            mRefreshing = refreshing;
//            if (mRefreshing) {
//                animateOffsetToCorrectPosition(mCurrentTargetOffsetTop, mRefreshListener);
//            } else {
//                startScaleDownAnimation(mRefreshListener);
//            }
//        }
//    }
//
//    private void startScaleDownAnimation(Animation.AnimationListener listener) {
//        mScaleDownAnimation = new Animation() {
//            @Override
//            public void applyTransformation(float interpolatedTime, Transformation t) {
//                setAnimationProgress(1 - interpolatedTime);
//            }
//        };
//        mScaleDownAnimation.setDuration(SCALE_DOWN_DURATION);
//        mCircleView.setAnimationListener(listener);
//        mCircleView.clearAnimation();
//        mCircleView.startAnimation(mScaleDownAnimation);
//    }
//
//    private void startProgressAlphaStartAnimation() {
//        mAlphaStartAnimation = startAlphaAnimation(mProgress.getAlpha(), STARTING_PROGRESS_ALPHA);
//    }
//
//    private void startProgressAlphaMaxAnimation() {
//        mAlphaMaxAnimation = startAlphaAnimation(mProgress.getAlpha(), MAX_ALPHA);
//    }
//
//    private Animation startAlphaAnimation(final int startingAlpha, final int endingAlpha) {
//        // Pre API_URL 11, alpha is used in place of scale. Don't also use it to
//        // show the trigger point.
//        if (mScale && isAlphaUsedForScale()) {
//            return null;
//        }
//        Animation alpha = new Animation() {
//            @Override
//            public void applyTransformation(float interpolatedTime, Transformation t) {
//                mProgress
//                        .setAlpha((int) (startingAlpha+ ((endingAlpha - startingAlpha)
//                                * interpolatedTime)));
//            }
//        };
//        alpha.setDuration(ALPHA_ANIMATION_DURATION);
//        // Clear out the previous animation listeners.
//        mCircleView.setAnimationListener(null);
//        mCircleView.clearAnimation();
//        mCircleView.startAnimation(alpha);
//        return alpha;
//    }
//
//    /**
//     * Set the background color of the progress spinner disc.
//     *
//     * @param colorRes Resource id of the color.
//     */
//    public void setProgressBackgroundColor(int colorRes) {
//        mCircleView.setBackgroundColor(colorRes);
//        mProgress.setBackgroundColor(getResources().getColor(colorRes));
//    }
//
//    /**
//     * @deprecated Use {@link #setColorSchemeResources(int...)}
//     */
//    @Deprecated
//    public void setColorScheme(int... colors) {
//        setColorSchemeResources(colors);
//    }
//
//    /**
//     * Set the color resources used in the progress animation from color resources.
//     * The first color will also be the color of the bar that grows in response
//     * to a user swipe gesture.
//     *
//     * @param colorResIds
//     */
//    public void setColorSchemeResources(int... colorResIds) {
//        final Resources res = getResources();
//        int[] colorRes = new int[colorResIds.length];
//        for (int i = 0; i < colorResIds.length; i++) {
//            colorRes[i] = res.getColor(colorResIds[i]);
//        }
//        setColorSchemeColors(colorRes);
//    }
//
//    /**
//     * Set the colors used in the progress animation. The first
//     * color will also be the color of the bar that grows in response to a user
//     * swipe gesture.
//     *
//     * @param colors
//     */
//    public void setColorSchemeColors(int... colors) {
//        ensureTarget();
//        mProgress.setColorSchemeColors(colors);
//    }
//
//    /**
//     * @return Whether the SwipeRefreshWidget is actively showing refresh
//     *         progress.
//     */
//    public boolean isRefreshing() {
//        return mRefreshing;
//    }
//
//    private void ensureTarget() {
//        // Don't bother getting the parent height if the parent hasn't been laid
//        // out yet.
//        if (mTarget == null) {
//            for (int i = 0; i < getChildCount(); i++) {
//                View child = getChildAt(i);
//                if (!child.equals(mCircleView)) {
//                    mTarget = child;
//                    break;
//                }
//            }
//        }
//    }
//
//    /**
//     * Set the distance to trigger a sync in dips
//     *
//     * @param distance
//     */
//    public void setDistanceToTriggerSync(int distance) {
//        mTotalDragDistance = distance;
//    }
//
//    @Override
//    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
//        final int width = getMeasuredWidth();
//        final int height = getMeasuredHeight();
//        if (getChildCount() == 0) {
//            return;
//        }
//        if (mTarget == null) {
//            ensureTarget();
//        }
//        if (mTarget == null) {
//            return;
//        }
//        final View child = mTarget;
//        final int childLeft = getPaddingLeft();
//        final int childTop = getPaddingTop();
//        final int childWidth = width - getPaddingLeft() - getPaddingRight();
//        final int childHeight = height - getPaddingTop() - getPaddingBottom();
//        child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
//        int circleWidth = mCircleView.getMeasuredWidth();
//        int circleHeight = mCircleView.getMeasuredHeight();
//        mCircleView.layout((width / 2 - circleWidth / 2), mCurrentTargetOffsetTop,
//                (width / 2 + circleWidth / 2), mCurrentTargetOffsetTop + circleHeight);
//    }
//
//    @Override
//    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//        if (mTarget == null) {
//            ensureTarget();
//        }
//        if (mTarget == null) {
//            return;
//        }
//        mTarget.measure(MeasureSpec.makeMeasureSpec(
//                getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
//                MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
//                getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY));
//        mCircleView.measure(MeasureSpec.makeMeasureSpec(mCircleWidth, MeasureSpec.EXACTLY),
//                MeasureSpec.makeMeasureSpec(mCircleHeight, MeasureSpec.EXACTLY));
//        if (!mUsingCustomStart && !mOriginalOffsetCalculated) {
//            mOriginalOffsetCalculated = true;
//            mCurrentTargetOffsetTop = mOriginalOffsetTop = -mCircleView.getMeasuredHeight();
//        }
//        mCircleViewIndex = -1;
//        // Get the index of the circleview.
//        for (int index = 0; index < getChildCount(); index++) {
//            if (getChildAt(index) == mCircleView) {
//                mCircleViewIndex = index;
//                break;
//            }
//        }
//    }
//
//    /**
//     * @return Whether it is possible for the child view of this layout to
//     *         scroll up. Override this if the child view is a custom view.
//     */
//    public boolean canChildScrollUp() {
//        if (android.os.Build.VERSION.SDK_INT < 14) {
//            if (mTarget instanceof AbsListView) {
//                final AbsListView absListView = (AbsListView) mTarget;
//                return absListView.getChildCount() > 0
//                        && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
//                        .getTop() < absListView.getPaddingTop());
//            } else {
//                //Log.d(TAG, "canChildScrollUp :"+ mTarget.getScrollY()+" "+mTarget);
//                boolean flag = mTarget.getScrollY() > 0;
//                if(mTarget instanceof RecyclerView) {
//                    RecyclerView rv = (RecyclerView) mTarget;
//                    int firstVisiblePosition = rv.getChildPosition(rv.getChildAt(0));
//                    if (firstVisiblePosition == 0)
//                        return rv.getChildAt(0).getTop() == 0 ? false:true;
//                    else
//                        return true;
//                }
//                return flag;//ViewCompat.canScrollVertically(mTarget, -1);
//            }
//        } else {
//            return ViewCompat.canScrollVertically(mTarget, -1);
//        }
//    }
//
//    @Override
//    public boolean onInterceptTouchEvent(MotionEvent ev) {
//        ensureTarget();
//
//        final int action = MotionEventCompat.getActionMasked(ev);
//
//        if (mReturningToStart && action == MotionEvent.ACTION_DOWN) {
//            mReturningToStart = false;
//        }
//
//        if (!isEnabled() || mReturningToStart || canChildScrollUp() || mRefreshing) {
//            // Fail fast if we're not in a state where a swipe is possible
//            return false;
//        }
//
//        switch (action) {
//            case MotionEvent.ACTION_DOWN:
//                setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCircleView.getTop(), true);
//                mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
//                mIsBeingDragged = false;
//                final float initialMotionY = getMotionEventY(ev, mActivePointerId);
//                if (initialMotionY == -1) {
//                    return false;
//                }
//                mInitialMotionY = initialMotionY;
//
//            case MotionEvent.ACTION_MOVE:
//                if (mActivePointerId == INVALID_POINTER) {
//                    Log.e(LOG_TAG, "Got ACTION_MOVE event but don't have an active pointer id.");
//                    return false;
//                }
//
//                final float y = getMotionEventY(ev, mActivePointerId);
//                if (y == -1) {
//                    return false;
//                }
//                final float yDiff = y - mInitialMotionY;
//                if (yDiff > mTouchSlop && !mIsBeingDragged) {
//                    mIsBeingDragged = true;
//                    mProgress.setAlpha(STARTING_PROGRESS_ALPHA);
//                }
//                break;
//
//            case MotionEventCompat.ACTION_POINTER_UP:
//                onSecondaryPointerUp(ev);
//                break;
//
//            case MotionEvent.ACTION_UP:
//            case MotionEvent.ACTION_CANCEL:
//                mIsBeingDragged = false;
//                mActivePointerId = INVALID_POINTER;
//                break;
//        }
//
//        return mIsBeingDragged;
//    }
//
//    private float getMotionEventY(MotionEvent ev, int activePointerId) {
//        final int index = MotionEventCompat.findPointerIndex(ev, activePointerId);
//        if (index < 0) {
//            return -1;
//        }
//        return MotionEventCompat.getY(ev, index);
//    }
//
//    @Override
//    public void requestDisallowInterceptTouchEvent(boolean b) {
//        // Nope.
//    }
//
//    private boolean isAnimationRunning(Animation animation) {
//        return animation != null && animation.hasStarted() && !animation.hasEnded();
//    }
//
//    @Override
//    public boolean onTouchEvent(MotionEvent ev) {
//        final int action = MotionEventCompat.getActionMasked(ev);
//
//        if (mReturningToStart && action == MotionEvent.ACTION_DOWN) {
//            mReturningToStart = false;
//        }
//
//        if (!isEnabled() || mReturningToStart || canChildScrollUp()) {
//            // Fail fast if we're not in a state where a swipe is possible
//            return false;
//        }
//
//        switch (action) {
//            case MotionEvent.ACTION_DOWN:
//                mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
//                mIsBeingDragged = false;
//                break;
//
//            case MotionEvent.ACTION_MOVE: {
//                final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
//                if (pointerIndex < 0) {
//                    Log.e(LOG_TAG, "Got ACTION_MOVE event but have an invalid active pointer id.");
//                    return false;
//                }
//
//                final float y = MotionEventCompat.getY(ev, pointerIndex);
//                final float overscrollTop = (y - mInitialMotionY) * DRAG_RATE;
//                if (mIsBeingDragged) {
//                    mProgress.showArrow(true);
//                    float originalDragPercent = overscrollTop / mTotalDragDistance;
//                    if (originalDragPercent < 0) {
//                        return false;
//                    }
//                    float dragPercent = Math.min(1f, Math.abs(originalDragPercent));
//                    float adjustedPercent = (float) Math.max(dragPercent - .4, 0) * 5 / 3;
//                    float extraOS = Math.abs(overscrollTop) - mTotalDragDistance;
//                    float slingshotDist = mUsingCustomStart ? mSpinnerFinalOffset
//                            - mOriginalOffsetTop : mSpinnerFinalOffset;
//                    float tensionSlingshotPercent = Math.max(0,
//                            Math.min(extraOS, slingshotDist * 2) / slingshotDist);
//                    float tensionPercent = (float) ((tensionSlingshotPercent / 4) - Math.pow(
//                            (tensionSlingshotPercent / 4), 2)) * 2f;
//                    float extraMove = (slingshotDist) * tensionPercent * 2;
//
//                    int targetY = mOriginalOffsetTop
//                            + (int) ((slingshotDist * dragPercent) + extraMove);
//                    // where 1.0f is a full circle
//                    if (mCircleView.getVisibility() != View.VISIBLE) {
//                        mCircleView.setVisibility(View.VISIBLE);
//                    }
//                    if (!mScale) {
//                        ViewCompat.setScaleX(mCircleView, 1f);
//                        ViewCompat.setScaleY(mCircleView, 1f);
//                    }
//                    if (overscrollTop < mTotalDragDistance) {
//                        if (mScale) {
//                            setAnimationProgress(overscrollTop / mTotalDragDistance);
//                        }
//                        if (mProgress.getAlpha() > STARTING_PROGRESS_ALPHA
//                                && !isAnimationRunning(mAlphaStartAnimation)) {
//                            // Animate the alpha
//                            startProgressAlphaStartAnimation();
//                        }
//                        float strokeStart = (float) (adjustedPercent * .8f);
//                        mProgress.setStartEndTrim(0f, Math.min(MAX_PROGRESS_ANGLE, strokeStart));
//                        mProgress.setArrowScale(Math.min(1f, adjustedPercent));
//                    } else {
//                        if (mProgress.getAlpha() < MAX_ALPHA
//                                && !isAnimationRunning(mAlphaMaxAnimation)) {
//                            // Animate the alpha
//                            startProgressAlphaMaxAnimation();
//                        }
//                    }
//                    float rotation = (-0.25f + .4f * adjustedPercent + tensionPercent * 2) * .5f;
//                    mProgress.setProgressRotation(rotation);
//                    setTargetOffsetTopAndBottom(targetY - mCurrentTargetOffsetTop,
//                            true /* requires update */);
//                }
//                break;
//            }
//            case MotionEventCompat.ACTION_POINTER_DOWN: {
//                final int index = MotionEventCompat.getActionIndex(ev);
//                mActivePointerId = MotionEventCompat.getPointerId(ev, index);
//                break;
//            }
//
//            case MotionEventCompat.ACTION_POINTER_UP:
//                onSecondaryPointerUp(ev);
//                break;
//
//            case MotionEvent.ACTION_UP:
//            case MotionEvent.ACTION_CANCEL: {
//                if (mActivePointerId == INVALID_POINTER) {
//                    if (action == MotionEvent.ACTION_UP) {
//                        Log.e(LOG_TAG, "Got ACTION_UP event but don't have an active pointer id.");
//                    }
//                    return false;
//                }
//                final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
//                final float y = MotionEventCompat.getY(ev, pointerIndex);
//                final float overscrollTop = (y - mInitialMotionY) * DRAG_RATE;
//                mIsBeingDragged = false;
//                if (overscrollTop > mTotalDragDistance) {
//                    setRefreshing(true, true /* notify */);
//                } else {
//                    // cancel refresh
//                    mRefreshing = false;
//                    mProgress.setStartEndTrim(0f, 0f);
//                    Animation.AnimationListener listener = null;
//                    if (!mScale) {
//                        listener = new Animation.AnimationListener() {
//
//                            @Override
//                            public void onAnimationStart(Animation animation) {
//                            }
//
//                            @Override
//                            public void onAnimationEnd(Animation animation) {
//                                if (!mScale) {
//                                    startScaleDownAnimation(null);
//                                }
//                            }
//
//                            @Override
//                            public void onAnimationRepeat(Animation animation) {
//                            }
//
//                        };
//                    }
//                    animateOffsetToStartPosition(mCurrentTargetOffsetTop, listener);
//                    mProgress.showArrow(false);
//                }
//                mActivePointerId = INVALID_POINTER;
//                return false;
//            }
//        }
//
//        return true;
//    }
//
//    private void animateOffsetToCorrectPosition(int from, Animation.AnimationListener listener) {
//        mFrom = from;
//        mAnimateToCorrectPosition.reset();
//        mAnimateToCorrectPosition.setDuration(ANIMATE_TO_TRIGGER_DURATION);
//        mAnimateToCorrectPosition.setInterpolator(mDecelerateInterpolator);
//        if (listener != null) {
//            mCircleView.setAnimationListener(listener);
//        }
//        mCircleView.clearAnimation();
//        mCircleView.startAnimation(mAnimateToCorrectPosition);
//    }
//
//    private void animateOffsetToStartPosition(int from, Animation.AnimationListener listener) {
//        if (mScale) {
//            // Scale the item back down
//            startScaleDownReturnToStartAnimation(from, listener);
//        } else {
//            mFrom = from;
//            mAnimateToStartPosition.reset();
//            mAnimateToStartPosition.setDuration(ANIMATE_TO_START_DURATION);
//            mAnimateToStartPosition.setInterpolator(mDecelerateInterpolator);
//            if (listener != null) {
//                mCircleView.setAnimationListener(listener);
//            }
//            mCircleView.clearAnimation();
//            mCircleView.startAnimation(mAnimateToStartPosition);
//        }
//    }
//
//    private final Animation mAnimateToCorrectPosition = new Animation() {
//        @Override
//        public void applyTransformation(float interpolatedTime, Transformation t) {
//            int targetTop = 0;
//            int endTarget = 0;
//            if (!mUsingCustomStart) {
//                endTarget = (int) (mSpinnerFinalOffset - Math.abs(mOriginalOffsetTop));
//            } else {
//                endTarget = (int) mSpinnerFinalOffset;
//            }
//            targetTop = (mFrom + (int) ((endTarget - mFrom) * interpolatedTime));
//            int offset = targetTop - mCircleView.getTop();
//            setTargetOffsetTopAndBottom(offset, false /* requires update */);
//        }
//    };
//
//    private void moveToStart(float interpolatedTime) {
//        int targetTop = 0;
//        targetTop = (mFrom + (int) ((mOriginalOffsetTop - mFrom) * interpolatedTime));
//        int offset = targetTop - mCircleView.getTop();
//        setTargetOffsetTopAndBottom(offset, false /* requires update */);
//    }
//
//    private final Animation mAnimateToStartPosition = new Animation() {
//        @Override
//        public void applyTransformation(float interpolatedTime, Transformation t) {
//            moveToStart(interpolatedTime);
//        }
//    };
//
//    private void startScaleDownReturnToStartAnimation(int from,
//                                                      Animation.AnimationListener listener) {
//        mFrom = from;
//        if (isAlphaUsedForScale()) {
//            mStartingScale = mProgress.getAlpha();
//        } else {
//            mStartingScale = ViewCompat.getScaleX(mCircleView);
//        }
//        mScaleDownToStartAnimation = new Animation() {
//            @Override
//            public void applyTransformation(float interpolatedTime, Transformation t) {
//                float targetScale = (mStartingScale + (-mStartingScale  * interpolatedTime));
//                setAnimationProgress(targetScale);
//                moveToStart(interpolatedTime);
//            }
//        };
//        mScaleDownToStartAnimation.setDuration(SCALE_DOWN_DURATION);
//        if (listener != null) {
//            mCircleView.setAnimationListener(listener);
//        }
//        mCircleView.clearAnimation();
//        mCircleView.startAnimation(mScaleDownToStartAnimation);
//    }
//
//    private void setTargetOffsetTopAndBottom(int offset, boolean requiresUpdate) {
//        mCircleView.bringToFront();
//        mCircleView.offsetTopAndBottom(offset);
//        mCurrentTargetOffsetTop = mCircleView.getTop();
//        if (requiresUpdate && android.os.Build.VERSION.SDK_INT < 11) {
//            invalidate();
//        }
//    }
//
//    private void onSecondaryPointerUp(MotionEvent ev) {
//        final int pointerIndex = MotionEventCompat.getActionIndex(ev);
//        final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
//        if (pointerId == mActivePointerId) {
//            // This was our active pointer going up. Choose a new
//            // active pointer and adjust accordingly.
//            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
//            mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
//        }
//    }
//
//    /**
//     * Classes that wish to be notified when the swipe gesture correctly
//     * triggers a refresh should implement this interface.
//     */
//    public interface OnRefreshListener {
//        public void onRefresh();
//    }
//}